Abraxus's Blog

Circle City Con Guardian Write Up

Details:

Jeopardy style CTF

Category: Reverse Engineering

Write up:

Looking at the main function I saw:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  const char *v3; 
  const char *v4; 
  size_t v5;
  char *v6;
  __int64 v7; 

  setup(argc, argv, envp);
  v3 = (const char *)getflag();
  if ( !v3 )
    goto LABEL_12;
  v4 = v3;
  v5 = strlen(v3);
  v6 = (char *)calloc(1uLL, v5 + 2);
  if ( !v6 )
    goto LABEL_12;
  __printf_chk(1LL, "%s\n\nHOOOOOOOOOO Goes there? Do you have the password?\n> ", owl);
  if ( !fgets(v6, (int)v5 + 1, stdin) )
    goto LABEL_12;
  if ( v5 )
  {
    v7 = 0LL;
    while ( v6[v7] == v4[v7] )
    {
      ++v7;
      __printf_chk(1LL, byte_200F);
      if ( (v7 & 7) != 0 )
      {
        if ( v7 == v5 )
          goto LABEL_10;
      }
      else
      {
        putchar(10);
        if ( v7 == v5 )
          goto LABEL_10;
      }
    }
    puts("\nHoo hoo hoo!\nThat is incorrect, my guardian.");
LABEL_12:
    exit(0);
  }
LABEL_10:
  puts("\nWe will do our best.....you have fought well.");
  return 0;
}

I noticed the checkflag function and took a look at that as well:

char *getflag()
{
  FILE *v0; 
  int v1; 
  __off_t v2;
  char *v3; 
  char *v4;
  void *v6;
  struct stat v7;
  unsigned __int64 v8; 

  v8 = __readfsqword(0x28u);
  v0 = fopen("flag.txt", "r");
  v1 = fileno(v0);
  __fxstat(1, v1, &v7);
  v2 = v7.st_size;
  v3 = (char *)calloc(1uLL, v7.st_size + 2);
  if ( fread(v3, 1uLL, v2 + 1, v0) )
  {
    v4 = &v3[v2];
    if ( *v4 == 10 )
      *v4 = 0;
  }
  else
  {
    v6 = v3;
    v3 = 0LL;
    free(v6);
  }
  fclose(v0);
  return v3;
}

What I got from this is that we could connect and simply brute force the flag one character at a time by reading how many check marks were sent, every 8 characters there would be a new line character added which would mess with our script.

For this one I was fairly lazy and just manually added the new line each time and near the end I ended up with the following:

from pwn import *

#flag = "CCC{let_"
# final flag
flag = "CCC{let_m3_thr0ugh!_let_me_p4ss!_d0_y0u_th1nk_y0u_c4n_h3r?"

# how many items are in the output array when there are no new knowns
cur = 2

# check for the while loop, if nothing new is found then exit, this was mainly for testing
check = True
while (check):
	check = False

  # brute force all the possible characters
	for i in range(32, 127):
		i = chr(i)
		s = remote("35.224.135.84", 2000)

		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		s.sendline(flag + i + "}")
    # these were added each iteration
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		(s.recvline())
		output = str(s.recvline()).split(" ")

    # parse the output
		if len(output) > cur:
			print(output)
			cur = len(output)
			print(cur)
			flag += i
			print(flag)
			check = True
			break
		(s.recvline())